# -*- encoding: utf-8 -*-

from osv import fields,osv
from osv.orm import browse_record
import tools
from functools import partial
import pytz
import pooler
from tools.translate import _
from service import security
import netsvc
import datetime

general_state = (
    ('draft', _('Draft')),
    ('confirmed', _('Confirmed')),
    ('approved', _('Approved')),
)


class aas_room(osv.osv):
    _name = 'aas.room'
    _description = 'Phòng học'
    _columns = {
        'name': fields.char('Tên phòng học', size=64, required=True),
        'capacity': fields.integer('Sức chứa',), 
    }
    _sql_constraints = [
#        ('name_uniq', 'UNIQUE(name)', 'The name of the room must be unique!'),
    ]
    
    def copy(self, cr, uid, id, default=None, context=None):
        if not default:
            default = {}
        room = self.browse(cr, uid, id, context=context)
        default.update({
            'name': room.name + ' (copied)',
        })
        return super(aas_room, self).copy(cr, uid, id, default, context)
    
    def get_rooms_str(self, cr, uid, ids, context=None):
        rooms_str = ''
        rooms_ids = self.search(cr, uid, [('id', 'in', ids)], context=context)
        if rooms_ids:
            rooms_names = []
            for room in self.browse(cr, uid, rooms_ids, context=context):
                rooms_names.append(room.name)
            rooms_str = ', '.join(rooms_names)
        return rooms_str
    
    def get_rooms_from_str(self, cr, uid, rooms_str, context=None):
        rooms_codes = []
        try:
            if rooms_str:
                rooms_str = rooms_str.replace(' ', '')
                if rooms_str:
                    rooms_codes_str = rooms_str.split(',')
                    for code_str in rooms_codes_str:
                        rooms_codes.append(code_str)
        except:
            raise osv.except_osv(_('Lỗi!'), _("Tên phòng học không hợp lệ!"))
        rooms_ids = []
        for code in rooms_codes:
            ids = self.search(cr, uid, [('name', '=', code)], context=context)
            if not ids:
                raise osv.except_osv(_('Error!'), _("There's no room with name '%s'!" % (code,)))
            rooms_ids.extend(ids)
        rooms_ids = list(set(rooms_ids))
        return rooms_ids
    
aas_room()

class aas_period(osv.osv):
    
    def get_periods_str(self, cr, uid, ids, context=None):
        periods_str = ''
        periods_ids = self.search(cr, uid, [('id', 'in', ids)], context=context)
        if periods_ids:
            periods_names = []
            for period in self.browse(cr, uid, periods_ids, context=context):
                periods_names.append(period.name)
            periods_str = ', '.join(periods_names)
        return periods_str
    
    def get_periods_from_str(self, cr, uid, periods_str, context=None):
        periods_codes = []
        try:
            if periods_str:
                periods_str = periods_str.replace(' ', '')
                if periods_str:
                    periods_codes_str = periods_str.split(',')
                    for code_str in periods_codes_str:
                        periods_codes.append(int(code_str))
        except:
            raise osv.except_osv(_('Error!'), _("Invalid periods string!"))
        periods_ids = []
        for code in periods_codes:
            ids = self.search(cr, uid, [('code', '=', code)], context=context)
            if not ids:
                raise osv.except_osv(_('Error!'), _("There's no period with code '%s'!" % (code,)))
            periods_ids.extend(ids)
        periods_ids = list(set(periods_ids))
        return periods_ids
    
    _name = 'aas.period'
    _description = 'Ca học'
    _columns = {
        'name': fields.char('Tên ca học', size=64),
        'code': fields.integer('Tên ca học', required=True),
        'time_start': fields.char('Giờ bắt đầu', size=64),
        'time_end': fields.char('Giờ kết thúc', size=64),
    }
    _sql_constraints = [
#        ('code_uniq', 'UNIQUE(code)', 'The name of the period must be unique!'),
    ]
    _order = 'code'
    
    def write(self, cr, uid, ids, vals, context=None):
        if vals.has_key('code'):
            vals['name'] = str(vals['code'])
        return super(aas_period, self).write(cr, uid, ids, vals, context=context)
    
    def copy(self, cr, uid, id, default=None, context=None):
        if not default:
            default = {}
        default.update({
            'code': -1,
        })
        return super(aas_period, self).copy(cr, uid, id, default, context)
    
    def onchange_code(self, cr, uid, ids, code):
        result = {'value': {}}
        name = ''
        if code:
            name = str(code)
        result['value']['name'] = name
        return result
aas_period()


class aas_course_list(osv.osv):
    
    def action_request_wait(self, cr, uid, ids, context=None):
        vals = {'state': 'request_wait'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_request_done(self, cr, uid, ids, context=None):
        course_obj = self.pool.get('aas.course.course')
        for obj in self.browse(cr, uid, ids, context=context):
            courses_to_unlink = []
            for course in obj.courses:
                if course.state not in ('draft', 'confirmed', 'approved', 'refused', 'canceled'):
                    raise osv.except_osv(_('Lỗi!'), _("Cannot close a list of courses for register!"))
                if course.state in ('draft'):
                    courses_to_unlink.append(course.id)
            if len(courses_to_unlink):
                course_obj.unlink(cr, uid, courses_to_unlink, context=context)
        vals = {'state': 'request_done'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_register_wait(self, cr, uid, ids, context=None):
        course_obj = self.pool.get('aas.course.course')
        courses_ids = []
        for obj in self.browse(cr, uid, ids, context=context):
            for course in obj.courses:
                if course.state not in ('approved', 'refused', 'canceled'):
                    raise osv.except_osv(_('Error!'), _("Cannot open a list of courses for register! There'are courses not approved or refused!"))
                if course.state == 'approved':
                    courses_ids.append(course.id)
        course_obj.write(cr, uid, courses_ids, {'state': 'register_wait'}, context=context)
        vals = {'state': 'register_wait'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_register_done(self, cr, uid, ids, context=None):
        course_obj = self.pool.get('aas.course.course')
        courses_ids = []
        for obj in self.browse(cr, uid, ids, context=context):
            for course in obj.courses:
                if course.state not in ('register_wait', 'refused', 'merged', 'split', 'canceled'):
                    raise osv.except_osv(_('Error!'), _("Cannot close registering for a list of courses!"))
                if course.state == 'register_wait':
                    courses_ids.append(course.id)
        course_obj.write(cr, uid, courses_ids, {'state': 'register_done'}, context=context)
        vals = {'state': 'register_done'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_register_wait_re(self, cr, uid, ids, context=None):
        course_obj = self.pool.get('aas.course.course')
        courses_ids = []
        for obj in self.browse(cr, uid, ids, context=context):
            for course in obj.courses:
                if course.state not in ('refused', 'merged', 'split', 'register_done', 'canceled'):
                    raise osv.except_osv(_('Error!'), _("Cannot re-open a list of courses for register!"))
                if course.state in ('register_done'):
                    courses_ids.append(course.id)
        course_obj.write(cr, uid, courses_ids, {'state': 'register_wait'}, context=context)
        vals = {'state': 'register_wait'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_process(self, cr, uid, ids, context=None):
        vals = {'state': 'processing'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_operate(self, cr, uid, ids, context=None):
        course_obj = self.pool.get('aas.course.course')
        courses_ids = []
        for obj in self.browse(cr, uid, ids, context=context):
            for course in obj.courses:
                if course.state not in ('refused', 'merged', 'split', 'canceled', 'closed', 'operate_ready'):
                    raise osv.except_osv(_('Error!'), _("Cannot operate this list of courses!"))
                if course.state in ('operate_ready'):
                    courses_ids.append(course.id)
        course_obj.write(cr, uid, courses_ids, {'state': 'operating'}, context=context)
        vals = {'state': 'operating'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_finish(self, cr, uid, ids, context=None):
        course_obj = self.pool.get('aas.course.course')
        courses_ids = []
        for obj in self.browse(cr, uid, ids, context=context):
            for course in obj.courses:
                if course.state not in ('refused', 'merged', 'split', 'canceled', 'closed', 'operating', 'finished'):
                    raise osv.except_osv(_('Error!'), _("Cannot finish this list of courses!"))
                if course.state in ('operating'):
                    courses_ids.append(course.id)
        course_obj.write(cr, uid, courses_ids, {'state': 'finished'}, context=context)
        vals = {'state': 'finished'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_cancel(self, cr, uid, ids, context=None):
        course_obj = self.pool.get('aas.course.course')
        courses_ids = []
        for obj in self.browse(cr, uid, ids, context=context):
            for course in obj.courses:
                courses_ids.append(course.id)
        course_obj.write(cr, uid, courses_ids, {'state': 'canceled'}, context=context)
        vals = {'state': 'canceled'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def button_close(self, cr, uid, ids, context=False):
        course_obj = self.pool.get('aas.course.course')
        for obj in self.browse(cr, uid, ids, context=context):
            for course in obj.courses:
                if course.state not in ('closed'):
                    course_obj.button_close(cr, uid, [course.id], context=context)
        self.write(cr, uid, ids, {'state': 'closed'}, context=context)
        return True
    
    def button_open_request(self, cr, uid, ids, context=False):
        self.write(cr, uid, ids, {'state': 'request_wait'}, context=context)
        return True
    
    def button_close_request(self, cr, uid, ids, context=False):
        self.write(cr, uid, ids, {'state': 'request_closed'}, context=context)
        return True
    
    def button_open_register(self, cr, uid, ids, context=False):
        self.write(cr, uid, ids, {'state': 'register_wait'}, context=context)
        return True
    
    def button_close_register(self, cr, uid, ids, context=False):
        self.write(cr, uid, ids, {'state': 'register_closed'}, context=context)
        return True
    
    def onchange_year(self, cr, uid, ids, year, semester):
        res = {'value': {}}
        year_obj = self.pool.get('aas.academic.year')
        semester_obj = self.pool.get('aas.academic.semester')
        if not year: res['value'].update({'academic_semester': False})
        else:
            if semester:
                sql = '''
                    SELECT 1
                    FROM aas_academic_year aay JOIN aas_academic_semester aas ON aay.id = aas.academic_year
                    WHERE aay.id = %s AND aas.id = %s
                '''
                cr.execute(sql, (year, semester))
                if cr.rowcount == 0: res['value'].update({'academic_semester': False}) 
        return res
    
    def _default_academic_year(self, cr, uid, context=None):
        res = False
        year_obj = self.pool.get('aas.academic.year')
        current_academic_state = year_obj.get_current_academic_state(cr, uid, context=context)
        if current_academic_state[0]:
            res = current_academic_state[0].id
        return res
    
    def _default_academic_semester(self, cr, uid, context=None):
        res = False
        year_obj = self.pool.get('aas.academic.year')
        current_academic_state = year_obj.get_current_academic_state(cr, uid, context=context)
        if current_academic_state[1]:
            res = current_academic_state[1].id
        return res
    
    def is_in_current_academic_state(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        year_obj = self.pool.get('aas.academic.year')
        current_academic_state = year_obj.get_current_academic_state(cr, uid, context=context)
        for obj in self.browse(cr, uid, ids, context=context):
            result[obj.id] = False
            if current_academic_state[0] and current_academic_state[1]:
                if (obj.academic_year.id == current_academic_state[0].id) and (obj.academic_semester.id == current_academic_state[1].id):
                    result[obj.id] = True
        return result
    
    _name = 'aas.course.list'
    _description = 'Danh sách lớp môn học'
    _columns = {
        'name': fields.char('Tên danh sách lớp môn học', size=64, required=True),
        'academic_semester': fields.many2one('aas.academic.semester', string='Học kỳ', required=True, readonly=True, states={'draft': [('readonly', False)]}),
        'academic_year': fields.many2one('aas.academic.year', string='Năm học', required=True, readonly=True, states={'draft': [('readonly', False)]}),
        'state': fields.selection((('draft', _('Đang được xử lý')),
                                   ('request_wait', _('Đang tiếp nhận yêu cầu mở lớp')),
                                   ('request_closed', _('Đã ngừng tiếp nhận yêu cầu mở lớp')),
                                   ('register_wait', _('Đang cho đăng ký học phần')),
                                   ('register_closed', _('Đã ngừng đăng ký học phần')),
                                   ('closed', _('Đã đóng'))), string='Trạng thái', readonly=True),
        'courses': fields.one2many('aas.course.course', 'list_id', string='Danh sách lớp môn học', readonly=True, states={'request_wait': [('readonly', False)]}),
        'max_number_of_credits': fields.integer('Số tín chỉ tối đa cho phép đăng ký', required=True, readonly=True, states={'draft': [('readonly', False)], 
                                                                                                                           'request_wait': [('readonly', False)],
                                                                                                                           'request_closed': [('readonly', False)]}), 
        'is_in_current_academic_state': fields.function(is_in_current_academic_state, method=True, type='boolean', 
                                                        store={'trobz.property': (lambda self, cr, uid, ids, *a: self.pool.get('aas.course.list').search(cr, uid, []), ['value'], 100),
                                                               'aas.course.list': (lambda self, cr, uid, ids, *a: ids, ['academic_year', 'academic_semester'], 100)}),
    }
    _sql_constraints = [
    ]
    _defaults = {
        'name': lambda *a: '/',
        'state': lambda *a: 'draft',
        'academic_year': _default_academic_year,
        'academic_semester': _default_academic_semester,
        'max_number_of_credits': lambda *a: 25,
    }
    _order = 'academic_year desc, academic_semester desc'
    
    def confirm(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state': 'confirmed'})
        return True
    
    def approve(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state': 'approved'})
        return True
    
    def refuse(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state': 'draft'})
        return True
    
    def set_back_to_draft(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state': 'draft'})
        return True
    
    def copy(self, cr, uid, id, default=None, context=None):
        if not default:
            default = {}
        list_of_courses = self.browse(cr, uid, id, context=context)
        default.update({
            'name': list_of_courses.name + ' (copied)',
        })
        return super(aas_course_list, self).copy(cr, uid, id, default, context)
    
    def name_get(self, cr, uid, ids, context=None):
        res = []
        for obj in self.browse(cr, uid, ids, context=context):
            res.append((obj.id, 'Học kỳ ' + str(obj.academic_semester.name) + ', năm học ' + str(obj.academic_year.name)))
        return res
    
    def get_all_lines(self, cr, uid, id, context=None):
        result = []
        obj = self.browse(cr, uid, id, context=context)
        if obj:
            stt = 0
            for course in obj.courses:
                stt += 1
                ma_lop = course.name
                ten_mon_hoc = course.subject_id.name
                tong_so_tin_chi = course.total_credit
                giang_vien = course.lec_id and course.lec_id.name or ''
                thu = course.day
                ca = ''
                for period in course.periods:
                    if ca: ca += ','
                    ca += period.name 
                phong = course.room_id and course.room_id.name or ''
                toi_da_dk = course.max_reg
                da_dk = course.cur_reg
                ngay_thi = course.exam_date
                thu_thi = course.exam_day
                phong_thi = ''
                for room in course.exam_rooms:
                    if phong_thi: phong_thi += ','
                    phong_thi += room.name
                ca_thi = ''
                for period in course.exam_periods:
                    if ca_thi: ca_thi += ','
                    ca_thi += period.name
                ghi_chu_thi = course.exam_note
                ghi_chu_tkb = course.note
                result.append([stt,
                               ma_lop,
                               ten_mon_hoc,
                               tong_so_tin_chi,
                               giang_vien,
                               thu,
                               ca,
                               phong,
                               toi_da_dk,
                               da_dk,
                               ngay_thi,
                               phong_thi,
                               ca_thi,
                               ghi_chu_thi,
                               thu_thi,
                               ghi_chu_tkb])
        return result
    
aas_course_list()


class aas_course_course(osv.osv):
    
    def check_states(self, cr, uid, ids, objects, states, mode='and', context=None):
        res = True
        if not objects:
            if ids:
                objects = self.browse(cr, uid, ids, context=context)
        if objects:
            for obj in objects:
                if mode == 'and': 
                    res = res and obj.obj.state in states
                    if res == False:
                        break
                else: 
                    res = res or obj.obj.state in states
                    if res == True:
                        break
        return res
    
    def onchange_list_id(self, cr, uid, ids, list_id, context=None):
        result = {'value': {}}
        list_obj = self.pool.get('aas.course.list')
        if list_id:
            list = list_obj.browse(cr, uid, list_id, context=context)
            result['value']['academic_year'] = list.academic_year.id
            result['value']['academic_semester'] = list.academic_semester.id
        return result
    
    def onchange_subject_id(self, cr, uid, ids, subject_id, context=None):
        result = {'value': {}}
        subject_obj = self.pool.get('aas.subject.subject')
        if subject_id:
            subject = subject_obj.browse(cr, uid, subject_id, context=context)
            result['value']['th_credit'] = subject.th_credit
            result['value']['pr_credit'] = subject.pr_credit
            result['value']['min_mark'] = subject.min_mark
            result['value']['name'] = subject.name
            result['value']['code'] = subject.name
            result['value'].update(self.onchange_credit(cr, uid, ids, subject.th_credit, subject.pr_credit, context=context)['value'])
        return result
    
    def onchange_credit(self, cr, uid, ids, th_credit, pr_credit, context=None):
        result = {'value': {'total_credit': th_credit + pr_credit}}
        return result
    
    def _total_credit(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        for course in self.browse(cr, uid, ids, context=context):
            result[course.id] = course.th_credit + course.pr_credit
        return result
    
    def is_in_current_academic_state(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        year_obj = self.pool.get('aas.academic.year')
        current_academic_state = year_obj.get_current_academic_state(cr, uid, context=context)
        for obj in self.browse(cr, uid, ids, context=context):
            result[obj.id] = False
            if current_academic_state[0] and current_academic_state[1]:
                if (obj.academic_year.id == current_academic_state[0].id) and (obj.academic_semester.id == current_academic_state[1].id):
                    result[obj.id] = True
        return result
    
    def action_confirm(self, cr, uid, ids, context=None):
        vals = {'state': 'confirmed'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_approve(self, cr, uid, ids, context=None):
        vals = {'state': 'approved'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_refuse(self, cr, uid, ids, context=None):
        vals = {'state': 'refused'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_draft(self, cr, uid, ids, context=None):
        vals = {'state': 'draft'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_merge(self, cr, uid, ids, context=None):
        vals = {'state': 'merged'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_split(self, cr, uid, ids, context=None):
        vals = {'state': 'split'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_cancel(self, cr, uid, ids, context=None):
        vals = {'state': 'canceled'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_operate_ready(self, cr, uid, ids, context=None):
        list_obj = self.pool.get('aas.course.list')
        for course in self.browse(cr, uid, ids, context=context):
            list_obj.action_process(cr, uid, [course.list_id.id], context=context)
        vals = {'state': 'operate_ready'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_close(self, cr, uid, ids, context=None):
        list_obj = self.pool.get('aas.course.list')
        for course in self.browse(cr, uid, ids, context=context):
            list_obj.action_process(cr, uid, [course.list_id.id], context=context)
        vals = {'state': 'closed'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def action_finish(self, cr, uid, ids, context=None):
        vals = {'state': 'finished'}
        res = self.write(cr, uid, ids, vals, context=context)
        return res
    
    def change_periods_str(self, cr, uid, ids, periods_str):
        period_obj = self.pool.get('aas.period')
        periods_ids = period_obj.get_periods_from_str(cr, uid, periods_str)
        periods_str = period_obj.get_periods_str(cr, uid, periods_ids)
        return (periods_ids, periods_str)
    
    def change_rooms_str(self, cr, uid, ids, rooms_str):
        room_obj = self.pool.get('aas.room')
        rooms_ids = room_obj.get_rooms_from_str(cr, uid, rooms_str)
        rooms_str = room_obj.get_rooms_str(cr, uid, rooms_ids)
        return (rooms_ids, rooms_str)
    
    def onchange_periods_str(self, cr, uid, ids, periods_str):
        (periods_ids, periods_str) = self.change_periods_str(cr, uid, ids, periods_str)
        return {'value': {'periods_str': periods_str}}
    
    def onchange_exam_periods_str(self, cr, uid, ids, periods_str):
        (periods_ids, periods_str) = self.change_periods_str(cr, uid, ids, periods_str)
        return {'value': {'exam_periods_str': periods_str}}
    
    def onchange_exam_rooms_str(self, cr, uid, ids, rooms_str):
        (rooms_ids, rooms_str) = self.change_rooms_str(cr, uid, ids, rooms_str)
        return {'value': {'exam_rooms_str': rooms_str}}
    
    def onchange_exam_date(self, cr, uid, ids, exam_date):
        day = False
        if exam_date:
            day = self._get_day_from_date(cr, uid, exam_date)
        return {'value': {'exam_day': day}}
    
    def _get_day_from_date(self, cr, uid, date_input):
        res = -1
        days = {0: 'mon', 1: 'tue', 2: 'wed', 3: 'thu', 4: 'fri', 5: 'sat', 6: 'sun'}
        date = datetime.datetime.strptime(date_input, '%Y-%m-%d')
        res = days[date.weekday()]
        return res
    
    def function_exam_day(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        days = {0: 'mon', 1: 'tue', 2: 'wed', 3: 'thu', 4: 'fri', 5: 'sat', 6: 'sun'}
        for obj in self.browse(cr, uid, ids, context=context):
            day = False
            if obj.exam_date:
                day = self._get_day_from_date(cr, uid, obj.exam_date)
            res[obj.id] = day
        return res
    
    def default_list_id(self, cr, uid, context=False):
        res = False
        if not context: context = {}
        res = context.get('list_id', False)
        return res
    
    def function_cur_reg(self, cr, uid, ids, fields, args, context=False):
        res = {}
        for obj in self.browse(cr, uid, ids, context=context):
            n = 0
            if obj.course_students: n = len(obj.course_students)
            res[obj.id] = n
        return res
    
    def function_readonly(self, cr, uid, ids, fields, args, context=False):
        res = {}
        for obj in self.browse(cr, uid, ids, context=context):
            res[obj.id] = False
            if obj.list_id:
                if obj.list_id.state in ('request_closed', 'register_wait', 'register_closed', 'closed'):
                    res[obj.id] = True
        return res
    
    _name = 'aas.course.course'
    _description = 'Lớp môn học'
    _columns = {
        'readonly': fields.function(function_readonly, method=True, type='boolean', string=''),
        'name': fields.char('Mã lớp môn học', size=64, required=True),
        'list_id': fields.many2one('aas.course.list', string='Danh sách lớp môn học', required=True, domain=[('state', 'in', ('request_wait',))], 
                                   context={'search_default_is_in_current_academic_state':1}),
        'lec_id': fields.many2one('res.users', string='Giảng viên', required=False, domain=[('lecturer', '=', True)]),
        'room_id': fields.many2one('aas.room', string='Phòng học', required=False),
        'day': fields.selection((('mon', _('Thứ Hai')),
                                 ('tue', _('Thứ Ba')),
                                 ('wed', _('Thứ Tư')),
                                 ('thu', _('Thứ Năm')),
                                 ('fri', _('Thứ Sáu')),
                                 ('sat', _('Thứ Bảy')),
                                 ('sun', _('Chủ Nhật')),), string='Học vào', required=True),
        'exam_day': fields.function(function_exam_day, method=True, string='Thi vào', type='selection',
                                    selection=(('mon', _('Thứ Hai')),
                                               ('tue', _('Thứ Ba')),
                                               ('wed', _('Thứ Tư')),
                                               ('thu', _('Thứ Năm')),
                                               ('fri', _('Thứ Sáu')),
                                               ('sat', _('Thứ Bảy')),
                                               ('sun', _('Chủ Nhật')),)),
        'periods': fields.many2many('aas.period', 'aas_course_course_period_rel', 'course_id', 'period_id', 'Học vào các ca'),
        'periods_str': fields.char('Periods', size=64,),
        'academic_year': fields.related('list_id', 'academic_year', type='many2one', relation='aas.academic.year', string='Năm học', readonly=True,
                                        store={'aas.course.course': (lambda self, cr, uid, ids, *a: ids, ['list_id'], 10),
                                               'aas.course.list': (lambda self, cr, uid, ids, *a: self.pool.get('aas.course.course').search(cr, uid, [('list_id', 'in', ids)]), ['academic_year', 'academic_semester'], 10)}),
        'academic_semester': fields.related('list_id', 'academic_semester', type='many2one', relation='aas.academic.semester', string='Học kỳ', readonly=True,
                                        store={'aas.course.course': (lambda self, cr, uid, ids, *a: ids, ['list_id'], 10),
                                               'aas.course.list': (lambda self, cr, uid, ids, *a: self.pool.get('aas.course.course').search(cr, uid, [('list_id', 'in', ids)]), ['academic_year', 'academic_semester'], 10)}),
        'week_start': fields.integer('Học từ tuần',),
        'week_end': fields.integer('Học đến tuần',),
        'note': fields.text('Ghi chú'),
        'subject_id': fields.many2one('aas.subject.subject', string='Môn học', required=True),
        'th_credit': fields.integer('Số tín chỉ lý thuyết', required=True),
        'pr_credit': fields.integer('Số tín chỉ thực hành', required=True),
        'total_credit': fields.function(_total_credit, string='Tổng số tín chỉ', method=True, readonly=True, type='integer',
                                        store={'aas.course.course': (lambda self, cr, uid, ids, *a: ids, ['th_credit', 'pr_credit'], 10)}),
        'min_mark': fields.float('Số điểm tối thiểu yêu cầu', required=True, help='Thang 10 điểm tối đa.'),
        'percent1': fields.integer('% của cột điểm thứ nhất'),
        'percent2': fields.integer('% của cột điểm thứ hai'),
        'percent3': fields.integer('% của cột điểm thứ ba'),
        'course_students': fields.one2many('aas.course.student', 'course_id', 'Danh sách sinh viên của lớp môn học này'),
        'state': fields.selection((('draft', _('Đang được xử lý')),
                                   ('processing', _('Đang được giảng dạy')),
                                   ('closed', _('Đã đóng')),), string='Trạng thái', readonly=True),
        'opened': fields.boolean('Opened', help='Lớp môn học này được quyết định mở?'),
        'result_state': fields.selection(general_state, string='Trạng thái bảng điểm cập nhật', readonly=True),
        'is_in_current_academic_state': fields.function(is_in_current_academic_state, method=True, type='boolean', 
                                                        store={'trobz.property': (lambda self, cr, uid, ids, *a: self.pool.get('aas.course.course').search(cr, uid, []), ['value'], 100),
                                                               'aas.course.course': (lambda self, cr, uid, ids, *a: ids, ['list_id', 'academic_year', 'academic_semester'], 100),
                                                               'aas.course.list': (lambda self, cr, uid, ids, *a: self.pool.get('aas.course.course').search(cr, uid, [('list_id', 'in', ids)]), ['academic_year', 'academic_semester'], 100)}),
        'exam_date': fields.date('Ngày thi'),
        'exam_periods': fields.many2many('aas.period', 'aas_course_course_period_rel_exam', 'course_id', 'period_id', 'Các ca thi'),
        'exam_periods_str': fields.char('Periods', size=64,),
        'exam_rooms': fields.many2many('aas.room', 'aas_course_course_room_rel_exam', 'course_id', 'room_id', 'Các phòng thi'),
        'exam_rooms_str': fields.char('Rooms', size=64,),
        'exam_note': fields.text('Ghi chú'),
        'max_reg': fields.integer('Số lượng tối đa'),
        'cur_reg': fields.function(function_cur_reg, method=True, type='integer', string='Số lượng hiện tại'),
        
#        'mark_update_done': fields.boolean('Đã cập nhật xong bảng điểm?', readonly=True),
    }
    _defaults = {
        'list_id': default_list_id, 
        'th_credit': lambda *a: 0,
        'pr_credit': lambda *a: 0,
        'min_mark': lambda *a: 5.0,
        'state': lambda *a: 'draft',
        'periods_str': lambda *a: '',
        'day': lambda *a: 'mon',
        'max_reg': lambda *a: 100,
#        'mark_update_done': lambda *a: False,
    }
    _sql_constraints = [
    ]
    
    def button_close(self, cr, uid, ids, context=False):
        lists_ids = []
        close_parent = True
        for obj in self.browse(cr, uid, ids, context=context):
#            if obj.state in ('processing'):
#                if not obj.mark_update_done:
#                    raise osv.except_osv(_('Lỗi!'), _('Không thể đóng lớp môn học này khi kết quả bảng điểm chưa được cập nhật xong!\nMã lớp: %s') % (obj.name,))
            lists_ids.append(obj.list_id.id)
            if obj.list_id.state not in ('register_closed',):
                close_parent = False
        self.write(cr, uid, ids, {'state': 'closed'}, context=context)
        if close_parent:
            lists_ids = list(set(lists_ids))
            list_obj = self.pool.get('aas.course.list')
            list_obj.button_close(cr, uid, lists_ids, context=context)
        return True
    
    def button_open(self, cr, uid, ids, context=False):
        for obj in self.browse(cr, uid, ids, context=context):
            if obj.list_id.state not in ('register_closed',):
                raise osv.except_osv(_('Lỗi!'), _('Không thể mở lớp môn học này khi chưa kết thúc đăng ký học phần!\nMã lớp: %s') % (obj.name,))
        self.write(cr, uid, ids, {'state': 'processing'}, context=context)
        return True
    
    def check_list_states(self, cr, uid, list_id, states, context=None):
        res = False
        if list_id:
            list_obj = self.pool.get('aas.course.list')
            list = list_obj.browse(cr, uid, list_id, context=context)
            if list.state in states:
                res = True
        return res
    
    def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
        if not args:
            args = []
        if not context:
            context = {}
        if context.has_key('schedule_semester'):
            semester_id = context['schedule_semester']
            ids = [] 
            if semester_id:
                course_list_obj = self.pool.get('aas.course.list')
                course_lists_of_semester = course_list_obj.search(cr, uid, [('academic_semester', '=', semester_id)], context=context)
                if len(course_lists_of_semester):
                    for course_list in course_list_obj.browse(cr, uid, course_lists_of_semester):
                        for course in course_list.courses:
                            ids.append(course.id)
            args.append(('id', 'in', ids))
        return super(aas_course_course, self).search(cr, uid, args, limit=limit, order=order, context=context, count=count)
    
    def create(self, cr, uid, vals, context=None):
        if not context: context = {}
        
        list_id = vals.get('list_id', False)
        if list_id:
            if not self.check_list_states(cr, uid, list_id, ['request_wait'], context=context):
                raise osv.except_osv(_('Lỗi!'), _('Không thể tạo lớp môn học vì danh sách này chưa tiếp nhận yêu cầu mở lớp!'))
        periods_str = vals.get('periods_str', False)
        if periods_str:
            (periods_ids, periods_str) = self.change_periods_str(cr, uid, [], periods_str)
            vals.update({'periods': [(6, 0, periods_ids)]})
        
        periods_str = vals.get('exam_periods_str', False)
        if periods_str:
            (periods_ids, periods_str) = self.change_exam_periods_str(cr, uid, [], periods_str)
            vals.update({'exam_periods': [(6, 0, periods_ids)]})
            
        rooms_str = vals.get('exam_rooms_str', False)
        if rooms_str:
            (rooms_ids, rooms_str) = self.change_rooms_str(cr, uid, [], rooms_str)
            vals.update({'exam_rooms': [(6, 0, rooms_ids)]})
            
        return super(aas_course_course, self).create(cr, uid, vals, context=context)
    
    def write(self, cr, uid, ids, vals, context=None):
        periods_str = vals.get('periods_str', False)
        if periods_str:
            (periods_ids, periods_str) = self.change_periods_str(cr, uid, ids, periods_str)
            vals.update({'periods': [(6, 0, periods_ids)]})
        
        periods_str = vals.get('exam_periods_str', False)
        if periods_str:
            (periods_ids, periods_str) = self.change_periods_str(cr, uid, ids, periods_str)
            vals.update({'exam_periods': [(6, 0, periods_ids)]})
            
        rooms_str = vals.get('exam_rooms_str', False)
        if rooms_str:
            (rooms_ids, rooms_str) = self.change_rooms_str(cr, uid, ids, rooms_str)
            vals.update({'exam_rooms': [(6, 0, rooms_ids)]})
            
        return super(aas_course_course, self).write(cr, uid, ids, vals, context=context)
    
    def fields_view_get(self, cr, uid, view_id=False, view_type='form', context=None, toolbar=False, submenu=False):
        if view_type == 'tree':
            mode = context.get('mode', 0)
            if mode:
                print mode
                view_xml_id = 'aas_course_course_tree_view_timetable'
                if mode == 1: view_xml_id = 'aas_course_course_tree_view_exam'
                year_obj = self.pool.get('aas.academic.year')
                view_id = year_obj.get_view_id(cr, uid, 'aas_course', view_xml_id)
        result = super(aas_course_course, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
        if view_type == 'form':
            if not context: context = {}
            list_id = context.get('list_id', False)
            if list_id:
                if result.has_key('arch'):
                    result['arch'] = result['arch'].replace('<field name="list_id" colspan="2" on_change="onchange_list_id(list_id)" attrs="{\'readonly\':[(\'readonly\',\'=\',True)]}" modifiers="{&quot;readonly&quot;: [[&quot;readonly&quot;, &quot;=&quot;, true]], &quot;required&quot;: true}"/>',
                                                            '<field name="list_id" colspan="2" on_change="onchange_list_id(list_id)" attrs="{\'readonly\':[(\'readonly\',\'=\',True)]}" modifiers="{&quot;readonly&quot;: [[&quot;readonly&quot;, &quot;=&quot;, true]], &quot;required&quot;: true, &quot;readonly&quot;: true}"/>') 
        return result
aas_course_course()

class aas_course_student(osv.osv):
    
    def _get_object_ids_from_objects(self, cr, uid, ids, context=None):
        return ids
    
    def _get_object_ids_from_courses(self, cr, uid, ids, context=None):
        result = []
        sql = '''
            SELECT id
            FROM aas_course_student
            WHERE course_id IN %s
        '''
        cr.execute(sql, (tuple(ids + [-1, -1]),))
        if cr.rowcount > 0:
            result = [id for (id,) in cr.fetchall()]
            result = list(set(result))
        return result
    
    def _avg_mark(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        for course_student in self.browse(cr, uid, ids, context=context):
            course = course_student.course_id
            avg_mark = ((course_student.mark1 * course.percent1) + 
                        ((course_student.mark2 * course.percent2)) +  
                        ((course_student.mark3 * course.percent3))) / (100.0) 
            
            floor = float(int(avg_mark))
            mid = floor + 0.5
            ceil = floor + 1
            
            if avg_mark >= floor + 0.75:
                avg_mark = ceil
            elif avg_mark >= floor + 0.25:
                avg_mark = mid
            else:
                avg_mark = floor
            
            result[course_student.id] = avg_mark
        return result
    
    def function_does_pass(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        for course_student in self.browse(cr, uid, ids, context=context):
            res[course_student.id] = (course_student.avg_mark >= course_student.course_id.min_mark)
        return res
    
    def default_course_id(self, cr, uid, context=False):
        res = False
        if not context: context = {}
        res = context.get('course_id', False)
        return res
    
    def write(self, cr, uid, ids, vals, context=False):
        for obj in self.browse(cr, uid, ids, context=context):
            can = False
            if obj.course_id and obj.course_id.lec_id and obj.course_id.lec_id.id == uid:
                can = True
                for profile in obj.course_id.lec_id.profiles_ids:
                    if profile.name not in (u'Giảng viên',):
                        can = False
                        break
            if not can:
                raise osv.except_osv(_('Lỗi!'), _('Chỉ có giảng viên trực tiếp phụ trách lớp môn học này mới có thể cập nhật điểm số!'))
            
        return super(aas_course_student, self).write(cr, uid, ids, vals, context=context)
    
    _name = 'aas.course.student'
    _description = 'Danh sách sinh viên lớp môn học'
    _columns = {
        'name': fields.char('Name', size=64),
        'course_id': fields.many2one('aas.course.course', string='Lớp môn học', required=True, ondelete='cascade'),
        'student_id': fields.many2one('res.users', string='Sinh viên', required=True),
        'mark1': fields.float('Điểm số cột thứ nhất'),
        'mark2': fields.float('Điểm số cột thứ hai'),
        'mark3': fields.float('Điểm số cột thứ ba'),
        'avg_mark': fields.function(_avg_mark, method=True, type='float', string='Điểm trung bình chung môn học',
                                    store = {
                                        'aas.course.student': (_get_object_ids_from_objects, ['mark1', 'mark2', 'mark3'], 10),
                                        'aas.course.course': (_get_object_ids_from_courses, ['percent1', 'percent2', 'percent3'], 10)},),
        'does_pass': fields.function(function_does_pass, method=True, type='boolean', string='Hoàn thành?'),
        'note': fields.char('Note', size=64),
        'time_register': fields.datetime('Thời điểm đăng ký'),
        
        'course_name': fields.related('course_id', 'name', string='Mã lớp môn học', type='char', size=64),
        'lec_id': fields.related('course_id', 'lec_id', relation='res.users', string='Giảng viên', type='many2one'),
        'room_id': fields.related('course_id', 'room_id', relation='aas.room', string='Phòng học', type='many2one'),
        'day': fields.related('course_id', 'day', type='selection', selection=(('mon', _('Thứ Hai')),
                                 ('tue', _('Thứ Ba')),
                                 ('wed', _('Thứ Tư')),
                                 ('thu', _('Thứ Năm')),
                                 ('fri', _('Thứ Sáu')),
                                 ('sat', _('Thứ Bảy')),
                                 ('sun', _('Chủ Nhật')),), string='Học vào'),
        'periods': fields.related('course_id', 'periods', string='Các ca học', type='many2many', relation='aas.period',),
        'subject_id': fields.related('course_id', 'subject_id', relation='aas.subject.subject', string='Môn học', type='many2one'),
        'total_credit': fields.related('course_id', 'total_credit', type='integer', string='Tổng số tín chỉ'),
        'max_reg': fields.related('course_id', 'max_reg', type='integer', string='Số lượng tối đa'),
        'cur_reg': fields.related('course_id', 'cur_reg', type='integer', string='Số lượng hiện tại'),
    }
    _defaults = {
        'name': lambda *a: '/',
        'mark1': lambda *a: 0,
        'mark2': lambda *a: 0,
        'mark3': lambda *a: 0,
        'time_register': lambda *a: datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S'),
        'course_id': default_course_id,
    }
#    _order = 'course_id.academic_year'
    
    def fields_view_get(self, cr, uid, view_id=False, view_type='form', context=None, toolbar=False, submenu=False):
        if view_type == 'tree':
            mode = context.get('enrollment', 0)
            if mode:
                view_xml_id = 'aas_course_student_tree_view_enrollment'
                year_obj = self.pool.get('aas.academic.year')
                view_id = year_obj.get_view_id(cr, uid, 'aas_course', view_xml_id)
        result = super(aas_course_student, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
        return result
aas_course_student()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
